//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics.Contracts;
using System.Linq;

namespace $safeprojectname$.Service
{
    /// <summary>
    ///     The Factory instantiates the IFactory class
    ///     to be the application only object creator
    /// </summary>
    public static class Factory
    {
        /// <summary>
        ///     Creates an instance of the 'serviceType'
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public static object GetService(Type serviceType)
        {
            return Current.GetService(serviceType);
        }
        /// <summary>
        ///     Creates an instance ot the 'T'.
        /// </summary>
        /// <returns></returns>
        public static T CreateInstance<T>(Type implementor = null)
            where T : class, IService
        {
            return Current.CreateInstance<T>(implementor);
        }
        /// <summary>
        ///     Creates an instance of the 'type'
        /// </summary>
        /// <param name="type"></param>
        /// <param name="implementor"></param>
        /// <returns></returns>
        public static object CreateInstance(Type type, Type implementor = null)
        {
            return Current.CreateInstance(type, implementor);
        }
        /// <summary>
        ///     Creates the list of instance implementing asked type T.
        ///     Empty list for not registered types is returned.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>not null list of requested instances</returns>
        public static IEnumerable<T> CreateInstances<T>()
            where T : class, IService
        {
            return Current.CreateInstances<T>();
        }
        /// <summary>
        ///     Injects dependencies via setters. Intended for 'external framework' created instances, e.g. aspx Page
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="instance"></param>
        public static void Enrich<T>(T instance)
        {
            Current.Enrich(instance);
        }

        #region Provider
        /// <summary>
        ///     Gets the current factory
        /// </summary>
        /// <value>The current.</value>
        static IFactoryProvider Current
        {
            get { return Instance.Provider; }
        }
        #endregion Provider

        #region lazy instance
        // beforefieldinit off
        // see: http://www.yoda.arachsys.com/csharp/singleton.html
        // see: http://www.yoda.arachsys.com/csharp/beforefieldinit.html
        static class Instance
        {
            // beforefieldinit
            public static readonly IFactoryProvider Provider;
            static Instance()
            {
                Provider = CreateFactory();
            }

            /// <summary>
            ///     Creates the factory (i.e. instatiates it)
            /// </summary>
            /// <returns></returns>
            static IFactoryProvider CreateFactory()
            {
                var type = Global.Settings.FactoryProviderType;
                if (type.Is())
                {
                    try
                    {
                        var factory = Activator.CreateInstance(type) as IFactoryProvider;
                        if (factory.Is())
                        {
                            return factory;
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new ConfigurationErrorsException("Cannot instantiated provided IFactoryProvider of type '{0}'".FormatWith(Global.Settings.FactoryProviderType), ex);
                    }
                }
                throw new ConfigurationErrorsException("Missing or broken IFactoryProvider type setting. Check 'Project.Config' project/settings/factoryProviderType.");
            }
        }
        #endregion
    }
}